import { FetchAPI, PageParams, Pager, User, UserService } from '../../interface'
import * as fs from 'node:fs';
import * as utils from 'node:util';
import { getUserNoPassword, md5 } from '../../utils';
const writeFilePromise = utils.promisify(fs.writeFile);

export class UserServiceImpl implements UserService {
    private db_path: string;
    private items: User[];
    private mock_user?: User['username'];
    private saveFile: () => Promise<void> = async () => {
        await writeFilePromise(this.db_path, JSON.stringify(this.items, null, 2));
    }
    /**
     * @param db_path 存储路径
     * @param mock_user 是否支持mock用户登录，如果配置了用户，将要默认不需要主动登录，并且系统无法退出登录
     */
    constructor (db_path: string, mock_user?: User['username']) {
        if (!fs.existsSync(db_path)) {
            fs.writeFileSync(db_path, '[]');
        }
        this.db_path = db_path;
        this.items = JSON.parse(fs.readFileSync(db_path, 'utf-8'));
        this.mock_user = mock_user;
    }
    getUserByUsername = async (username: string) => {
        const user = this.items.find(p => p.username === username)
        return user && getUserNoPassword(user);
    };
    userCreate: FetchAPI<User[]> = async (items) => {
        if (items.length === 0) return { success: false, msg: '请至少添加一个用户' };
        const uniq = new Set(items.map(t => t.username).concat(this.items.map(t => t.username))).size === items.length + this.items.length;
        if (!uniq) {
            return { success: false, msg: '用户名重复' };
        }
        for(let item of items) {
            this.items.push({
                ...item,
                password: item.password && md5(item.password),
            });
        }
        await this.saveFile();
        return { success: true };
    };
    userDelete: FetchAPI<string[]> = async (usernames) => {
        const nameset = new Set(usernames);
        this.items = this.items.filter(p => {
            if (nameset.has(p.username) && !p.readonly) {
                // 删除用户触发更新删除回调
                this.deleteCallbacks.forEach(callback => callback(p.username));
                return false;
            } else {
                return true;
            }
        });
        await this.saveFile();
        return { success: true };
    };
    userUpdate: FetchAPI<Partial<User>> = async (item) => {
        this.items = this.items.map(p => {
            if (p.username === item.username) {
                return { ...p, ...item };
            } else {
                return p;
            }
        });
        await this.saveFile();
        return { success: true, }
    };
    userList: FetchAPI<PageParams<Partial<User>>, Pager<User>> = async (body) => {
        const { page = 1, pageSize = 10, params } = body;
        let list = this.items;
        if (params) {
            const { username, nickname, roles = [], readonly } = params;
            list = this.items.filter(p => {
                if (username && p.username !== username) return false;
                if (nickname && !p.nickname?.includes(nickname)) return false;
                if (roles.length) {
                    if (!p.roles || p.roles.length < roles.length) return false;
                    for(let role of roles) {
                        if (p.roles.indexOf(role) === -1) return false;
                    }
                }
                if (readonly !== undefined && p.readonly !== readonly) return false;
                return true;
            });
        }
        return {
            success: true,
            data: {
                total: list.length,
                list: list.slice((page - 1) * pageSize, page * pageSize).map(getUserNoPassword),
                page,
                pageSize,
            },
        }
    };
    async getUser(username: string, password: string) {
        const pwd = md5(password);
        const user = this.items.find(p => p.username === username && p.password === pwd);
        return user && getUserNoPassword(user)
    }
    async getLoginUser() {
        if (this.mock_user) {
            const user = this.items.find(p => p.username === this.mock_user);
            return user && getUserNoPassword(user);
        }
    }

    private deleteCallbacks: {(username: string): void}[] = []
    onDeleteUser(callback: (username: string) => void): void {
        this.deleteCallbacks.push(callback);
    }
    
}